#include "myjni.h"
#include "platform_config.h"
#include <termios.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include "minizip/unzip.h"
#include "utf8-unicode.h"
int fd_pri;
int epoll_threadfd;
int cmd_fd;
int ultra_fd;
int epoll_cmdfd;
int fd_led;
extern SysInf  SysInfor;
extern int threadSocketW;
int disp_set_para = 0;
static pthread_mutex_t mutex_gpsData_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mutex_gpsAreaData_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mutex_log_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mutex_block_rw = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mutex_offline_block_rw = PTHREAD_MUTEX_INITIALIZER;
extern char SMSReceiveBuffer[BUFFER_SIZE];
extern unsigned char GPRSLink_Flag;
int gps_error = 0;

static int epoll_register(int epoll_fd, int fd) {
    struct epoll_event  ev;
    int ret, flags;

    /* important: make the fd non-blocking */
    flags = fcntl(fd, F_GETFL);
    fcntl(fd, F_SETFL, flags | O_NONBLOCK);

    ev.events  = EPOLLIN;
    ev.data.fd = fd;
    do {
        ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
    } while (ret < 0 && errno == EINTR);
    LOGE("%s, fd=%d", __func__, fd);
    return ret;
}

int epoll_deregister(int epoll_fd, int fd) {
    int  ret;
    do {
        ret = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
    } while (ret < 0 && errno == EINTR);
    return ret;
}

int set_baudrate(const int fd, const char *bautrate) {
    struct termios ntermios;
    int speed_B[]={B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B921600};
    const char  *speed_arr[]={"B1200", "B2400", "B4800", "B9600", "B19200", "B38400", "B57600", "B115200", "B230400", "B921600"};
    uint32_t i;
    int err = -1;

    for (i = 0; i < sizeof(speed_B) / sizeof(speed_B[0]); i++) {
        if(!memcmp(bautrate, speed_arr[i], strlen(bautrate))) {
            err = 0;
            LOGE("set_baudrate = %d\n", speed_B[i]);
            tcflush(fd, TCIOFLUSH);
            if ((err = tcgetattr(fd,&ntermios)) != 0)
            {
                LOGE("tcgetattr(%d) = %d,errno %d\r\n", fd, err, errno);
                close(fd);
                return err;

            }
            ntermios.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
            ntermios.c_oflag &= ~OPOST;
            ntermios.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
            ntermios.c_cflag &= ~(CSIZE|PARENB);
            ntermios.c_cflag |= CS8;
            ntermios.c_cflag &= ~CRTSCTS;//no flow control
            tcsetattr(fd, TCSANOW, &ntermios);
            tcflush(fd, TCIOFLUSH);
            tcflush(fd, TCIOFLUSH);
            tcflush(fd, TCIOFLUSH);
            err = cfsetispeed(&ntermios, speed_B[i]);
            if (err)
            {
                LOGE("cfsetispeed.. errno..\r\n");
                close(fd);
                return err;
            }
            err = cfsetospeed(&ntermios, speed_B[i]);
            if (err)
            {
                LOGE("cfsetispeed.. errno..\r\n");
                close(fd);
                return err;
            }
            tcsetattr(fd,TCSANOW,&ntermios);
        }
    }
    return err;
}


static char *para_ip_index[4] = {
    "ip",
    "port",
    "terminalId",
    "carNum",
};
static char *para_depth_index[5] = {
    "depth",
    "ref_depth",
    "machine_width",
    "plough_model",
	"plough_care_id",
};

static char *para_angle_index[5] = {
    "angle",
    "a_sensor_height",
	"angle_b",
	"a_sensor_height_b",
	"sensor_model",
};
static char *ajust_depth_filename[3] = {
     "autoSetLow.zip", "autoSetMedium.zip", "autoSetHigh.zip"
};



extern unsigned int ultra_depth;
#define UNZIP_FILE "/data/local/tmp/ajust_depth.txt"
int led_angle_ajust_mode = 0;
int checkExFile() {
    int flags = 0;
    char path[64] = {0};
    unsigned int i = 0;
    char buf[255];
    FILE *fp;
    int found = -1;
    SysInf *p_sys = &SysInfor;

    for (i = 0; i < 3; i++) {
        sprintf(path, "/storage/card/%s", ajust_depth_filename[i]);
        if (access(path, F_OK) == 0) {
            found = 1;
            break;
        }
    }
    if (found > 0) {
        LOGE("found file %s", path);
        led_angle_ajust_mode = 1;
         if (unzip(path, NULL, PASSWD, "/data/local/tmp")) {
             LOGE("unzip %s err", path);
         } else {
             if (!access(UNZIP_FILE, F_OK)) {
                 fp = fopen(UNZIP_FILE, "r");
                 if (fp == NULL) {
                     LOGE("open %s fail,err[%s]", UNZIP_FILE,strerror(errno));
                 } else {
                     memset(buf, 0, sizeof(buf));
                     fgets(buf, sizeof(buf), fp);
                     int ajust_depth = atoi(buf);
                     int ref_temp = ajust_depth + ultra_depth;//校准算法，读取ajust_para.txt的值加上当前超声波真实距离
                     if ((ref_temp >= 600) && (ref_temp <= 1300)) {
                         p_sys->ref_depth = ref_temp;
                         disp_set_para = 1;
                     } else {
                         write_log_to_sdcard(LOG_TXT_PATH, "参考深度%d不在合理范围", ref_temp);
                     }
                     LOGE("ajust_val=%d, ultra_depth=%d, ref_depth=%d", ajust_depth, ultra_depth, p_sys->ref_depth);
                     fclose(fp);
                     remove(UNZIP_FILE);
                     write_log_to_sdcard(LOG_TXT_PATH, "校准零点 参考深度%dmm", p_sys->ref_depth);
                 }
             }
         }
         LOGE("unzip %s success", path);
    }



    sprintf(path, "/storage/card/%s", EX_PRIVATE_PAR);
    if (access(path, F_OK)) {
        return found;
    }
    fp = fopen(path, "r");
    if (fp == NULL)
        return found;
    char para[5][64];
    int ret;
    char *p_start, *p_end;

    memset(buf, 0, sizeof(buf));
    while (fgets(buf, sizeof(buf), fp)) {
        //LOGE("buf[0]=%c,%c,%c,%c,", buf[0], buf[1], buf[2], buf[3]);
         LOGE("para buf:%s", buf);
         if (strstr(buf, "#"))
             continue;
         p_start = strstr(buf, "depth=");
         memset(para, 0, sizeof(para));
         if (p_start) {
             for (i = 0; i < sizeof_arry(para_depth_index); i++) {
                 p_start = strstr(p_start, para_depth_index[i]);
                 if (p_start == NULL)
                     break;
                 p_start += strlen(para_depth_index[i]) + 1;
                 p_end = strchr(p_start, ';');
                 strncpy(para[i], p_start, p_end - p_start);
                 p_start = p_end;
                 LOGE("para[%d]:%s", i, para[i]);
             }
             if (i == sizeof_arry(para_depth_index)) {
                 p_sys->depth = atoi(para[0]);
                 int ref_temp = atoi(para[1]);//合理范围600-1300mm
                 if ((ref_temp >= 600) && (ref_temp <= 1300)) {
                     p_sys->ref_depth = ref_temp;
                 } else {
                     write_log_to_sdcard(LOG_TXT_PATH, "sdcard:参考深度不在合理范围");
                 }
                 p_sys->machine_width = atof(para[2]) * 100;
				 if (atof(para[3]) == 0 || atof(para[3]) == 1)
				 {
					 p_sys->plough_model = atof(para[3]);
				 }
				 else
				 {
					 p_sys->plough_model = 1;
				 }
				 strcpy(p_sys->plough_care_id, para[4]);
                 disp_set_para = 1;
                 write_log_to_sdcard(LOG_TXT_PATH, "sdcard:设置深度参数");

             }
             continue;
         }

         p_start = strstr(buf, "angle=");
         memset(para, 0, sizeof(para));
         if (p_start) {
             for (i = 0; i < sizeof_arry(para_angle_index); i++) {
                 p_start = strstr(p_start, para_angle_index[i]);
                 if (p_start == NULL)
                     break;
                 p_start += strlen(para_angle_index[i]) + 1;
                 p_end = strchr(p_start, ';');
                 strncpy(para[i], p_start, p_end - p_start);
                 p_start = p_end;
                 LOGE("para[%d]:%s", i, para[i]);
             }
             if (i == sizeof_arry(para_angle_index)) {
                 p_sys->angle = atoi(para[0]);
                 p_sys->a_sensor_height = atoi(para[1]);
				 p_sys->angle_b = atoi(para[2]);
				 p_sys->a_sensor_height_b = atoi(para[3]);
				 if (atoi(para[4]) == 0 || atoi(para[4]) == 1 || atoi(para[4]) == 2 || atoi(para[4]) == 3)
				 {
					 p_sys->sensor_model = atoi(para[4]);
				 }
				 else
				 {
					 p_sys->sensor_model = 1;
				 }
                 disp_set_para = 1;
                 write_log_to_sdcard(LOG_TXT_PATH, "sdcard:设置角度参数");

             }
             continue;
         }

         memset(para, 0, sizeof(para));
         p_start = strstr(buf, "ip=");
         if (p_start) {
             for (i = 0; i < sizeof_arry(para_ip_index); i++) {
                 p_start = strstr(p_start, para_ip_index[i]);
                 if (p_start == NULL)
                     break;
                 p_start += strlen(para_ip_index[i]) + 1;
                 p_end = strchr(p_start, ';');
                 if (!p_end)
                     p_end = strchr(p_start, '\n');
                 strncpy(para[i], p_start, p_end - p_start);
                 p_start = p_end;
                 LOGE("para[%d]:%s", i, para[i]);
             }
             if (i == sizeof_arry(para_ip_index)) {
                 memset(p_sys->IP, 0, 30);
                 memset(p_sys->terminalID, 0, sizeof(p_sys->terminalID));
                 memset(p_sys->LocalPhoneNum1, 0, sizeof(p_sys->LocalPhoneNum1));
                 memset(p_sys->CarNumber, 0, sizeof(p_sys->CarNumber));
                 memset(p_sys->CarNumber_utf8, 0, sizeof(p_sys->CarNumber_utf8));
                 sprintf(p_sys->IP,"%s", para[0]);
                 p_sys->port = atoi(para[1]);
                 sprintf(p_sys->terminalID, "%s", para[2]);
                 sprintf(p_sys->LocalPhoneNum1, "01861%s", para[2]);
                 p_sys->IP[sizeof(p_sys->IP) - 1] = 0; //防止参数过长溢出
                 p_sys->terminalID[sizeof(p_sys->terminalID) - 1] = 0;
                 p_sys->LocalPhoneNum1[sizeof(p_sys->LocalPhoneNum1) - 1] = 0;

                 int unicode;
                 char *p_int = (char *)&unicode;
                 strcpy(p_sys->CarNumber_utf8, para[3]);
                 int u_len = UTF8toUnicode((unsigned char *)para[3], &unicode);
                 sprintf(p_sys->CarNumber + 2, "%s", para[3] + u_len);
                 p_sys->CarNumber[sizeof(p_sys->CarNumber) - 1] = 0; //防止参数过长溢出
                 p_sys->CarNumber[0] = p_int[1];
                 p_sys->CarNumber[1] = p_int[0];
                 GPRSLink_Flag = 0; //reconnect network
                 disp_set_para = 1;
                 write_log_to_sdcard(LOG_TXT_PATH, "sdcard:设置IP参数");

             }
             continue;
         }
    }
    fclose(fp);

    return 1;
}

void split(char *buf) {
    char *ptr;
    char *p;
    char *data[10];
    int i = 0;

    memset(data, 0, sizeof(data));
    ptr = strtok(buf, ";");
    while (ptr) {
        LOGE("%s", ptr);
        data[i] = strdup(ptr);
        ptr = strtok(NULL, ";");
        if (++i >= 10)
            break;
    }
    for (i = 0; (i < 10) && data[i]; i++) {
        p = strstr(data[i], "car=");
        if (p) {
            p += 4;
            if (strlen(p) >= sizeof(SysInfor.CarNumber))
                continue;
            memset(SysInfor.CarNumber_utf8, 0, sizeof(SysInfor.CarNumber_utf8));
            memset(SysInfor.CarNumber, 0, sizeof(SysInfor.CarNumber));
            strcpy(SysInfor.CarNumber_utf8, p);
            int unicode;
            char *p_int = (char *)&unicode;
            int u_len = UTF8toUnicode((unsigned char *)p, &unicode);
            sprintf(SysInfor.CarNumber + 2, "%s", p + u_len);
            SysInfor.CarNumber[0] = p_int[1];
            SysInfor.CarNumber[1] = p_int[0];
            write_log_to_sdcard(LOG_TXT_PATH, "短信设置车牌号");
            continue;
        } 
        p = strstr(data[i], "port=");
        if (p) {
            p += 5;
            SysInfor.port = atoi(p);
            write_log_to_sdcard(LOG_TXT_PATH, "短信设置IP");
            continue;
        }
        p = strstr(data[i], "id=");
        if (p) {
            p += 3;
            if (strlen(p) >= sizeof(SysInfor.terminalID))
                continue;
            memset(SysInfor.terminalID, 0, sizeof(SysInfor.terminalID));
            strcpy(SysInfor.terminalID, p);
            memset(SysInfor.LocalPhoneNum1, 0, sizeof(SysInfor.LocalPhoneNum1));
            sprintf(SysInfor.LocalPhoneNum1, "01861%s", p);
            write_log_to_sdcard(LOG_TXT_PATH, "短信设置终端号");
            continue;
        }
        p = strstr(data[i], "ip=");
        if (p) {
            p += 3;
            if (strlen(p) >= sizeof(SysInfor.IP))
                continue;
            memset(SysInfor.IP, 0, sizeof(SysInfor.IP));
            strcpy(SysInfor.IP, p);
            continue;
        }

        p = strstr(data[i], "depth=");
        if (p) {
            p += 6;
            SysInfor.depth = atoi(p);
            write_log_to_sdcard(LOG_TXT_PATH, "短信设置默认深度");
            continue;
        }

        p = strstr(data[i], "refDepth=");
        if (p) {
            p += 9;
            int ref_temp = atoi(p);
            if ((ref_temp >= 600) && (ref_temp <= 1300)) {
                SysInfor.ref_depth = ref_temp;
            write_log_to_sdcard(LOG_TXT_PATH, "短信设置参考深度");
            } else {
                write_log_to_sdcard(LOG_TXT_PATH, "短信设置参考深度,无效");
            }
            continue;
        }
        p = strstr(data[i], "width=");
        if (p) {
            p += 6;
            SysInfor.machine_width = atof(p);
            continue;
        }
        p = strstr(data[i], "angle=");
        if (p) {
            p += 6;
            int angle = atoi(p);
            if (angle >= 0 && angle<=360) {
                SysInfor.angle = atoi(p);
                write_log_to_sdcard(LOG_TXT_PATH, "短信设置传感器角度");
            } else {
                write_log_to_sdcard(LOG_TXT_PATH, "短信设置传感器角度%d,无效", angle);
            }
            continue;
        }
        p = strstr(data[i], "angleH=");
        if (p) {
            p += 7;
            SysInfor.a_sensor_height = atoi(p);
            write_log_to_sdcard(LOG_TXT_PATH, "短信设置传感器高度");
            continue;
        }
    }
    for (i = 0; (i < 10) && data[i]; i++)
        free(data[i]);

    disp_set_para = 1;
    BlockWrite((char *)&SysInfor, SysInfLength, SYSINFO_SET);
}

void BlockRead(char *buf,int Length, int set) {
    pthread_mutex_lock(&mutex_block_rw);
    if (access(PRIVATE_PAR, F_OK)) {
        creat(PRIVATE_PAR, S_IRWXO);
        chmod(PRIVATE_PAR, S_IROTH|S_IWOTH|S_IRGRP|S_IWGRP|S_IRWXU|S_IRWXO|S_IRWXG);
        fd_pri = open(PRIVATE_PAR, O_RDWR);
        if (fd_pri < 0) {
            LOGE("open %s fail, err= %s\n", PRIVATE_PAR, strerror(errno));
            goto out;
        }
        lseek(fd_pri, 0, SEEK_SET);
        int i;
        char val = 0;
        for (i = 0; i < 4096; i++)
            write(fd_pri, &val, sizeof(val));
        close(fd_pri);
    }
    fd_pri = open(PRIVATE_PAR, O_RDWR);
    if (fd_pri < 0) {
        LOGE("open %s fail, err= %s\n", PRIVATE_PAR, strerror(errno));
        goto out;
    }
    lseek(fd_pri, set, SEEK_SET);
    read(fd_pri, buf, Length);
    close(fd_pri);
out:
    pthread_mutex_unlock(&mutex_block_rw);
}

void BlockWrite(char *buf,int Length, int set) {//gprs.bin
    char md5[33];

    pthread_mutex_lock(&mutex_block_rw);
    if (access(PRIVATE_PAR, F_OK)) {
        creat(PRIVATE_PAR, S_IRWXO);
        chmod(PRIVATE_PAR, S_IROTH|S_IWOTH|S_IRGRP|S_IWGRP|S_IRWXU|S_IRWXO|S_IRWXG);
        fd_pri = open(PRIVATE_PAR, O_RDWR);
        if (fd_pri < 0) {
            LOGE("open %s fail, err= %s\n", PRIVATE_PAR, strerror(errno));
            goto out;
        }
        lseek(fd_pri, 0, SEEK_SET);
        int i;
        char val = 0;
        for (i = 0; i < 4096; i++)
            write(fd_pri, &val, sizeof(val));
        close(fd_pri);
    }
    fd_pri = open(PRIVATE_PAR, O_RDWR);
    if (fd_pri < 0) {
        LOGE("open %s fail, err= %s\n", PRIVATE_PAR, strerror(errno));
        goto out;
    }
    lseek(fd_pri, set, SEEK_SET);
    write(fd_pri, buf, Length);
    close(fd_pri);
    sync();
    Compute_buf_md5(buf, md5, Length - sizeof(md5));
    memcpy(((SysInf *)buf)->md5, md5, sizeof(md5));
    at24c16_write(I2C1, 0, Length, (unsigned char *)buf);
    at24c16_write(I2C3, 0, Length, (unsigned char *)buf);

out:
    pthread_mutex_unlock(&mutex_block_rw);

}

int OfflineBlockRead(char *path, struct list_head *head, unsigned int data_size) {
    int fd;
    int count, i;
    unsigned char *data;
	int ret = 0;
    OFFLINE_DATA_LIST *data_list;

    pthread_mutex_lock(&mutex_offline_block_rw);
	if (access(path, F_OK)) {
		ret = -1;
		goto out;
	}
    fd = open(path, O_RDWR);
    if (fd < 0) {
		ret = -1;
        LOGE("open %s fail, err= %s\n", path, strerror(errno));
        goto out;
    }
    lseek(fd, 0, SEEK_SET);
    ret = read(fd, &count, sizeof(count));
    if (ret != sizeof(count) || count < 0 || count > GPS_MAX_DATA) {
        close(fd);
        ret = 0;
        goto out;
    }

    pthread_mutex_lock(&mutex_list);
    //struct list_head temp_head;
    //INIT_LIST_HEAD(&temp_head);
    for (i = 0; i < count; i++) {
        data = malloc(data_size);
        read(fd, data, data_size);
        data_list = malloc(sizeof(OFFLINE_DATA_LIST));
        data_list->len = data_size;
        data_list->data = data;
        list_add_tail(&data_list->list, head);//读出来的顺序是1,2,3
    }
    //list_splice(&temp_head, head);//合并两个链表，离线数据为1,2,3,断电期间数据为4,5,6，那么合并后的数据顺序为1,2,3,4,5,6
    pthread_mutex_unlock(&mutex_list);
    ftruncate(fd, 0);//读完后清空文件
    close(fd);
    ret = count;
out:
	pthread_mutex_unlock(&mutex_offline_block_rw);
	return ret;

}


int OfflineBlockClear(char* path) {
	int ret = 0;
	int fd;

	pthread_mutex_lock(&mutex_offline_block_rw);
	if (access(path, F_OK)) {
		ret = -1;
		goto out;
	}
	fd = open(path, O_RDWR);
	if (fd < 0) {
		ret = -1;
		LOGE("open %s fail, err= %s\n", path, strerror(errno));
		goto out;
	}
	ftruncate(fd, 0);//清空文件
	close(fd);
out:
    pthread_mutex_unlock(&mutex_offline_block_rw);
    return ret;

}

int OfflineBlockWrite(char *path, struct list_head *head) {
    int fd;
    int count;
    int ret = 0;
    OFFLINE_DATA_LIST *data_list, *temp_list;

    pthread_mutex_lock(&mutex_offline_block_rw);
    pthread_mutex_lock(&mutex_list);
    if (list_empty_careful(head))
        goto out;
    if (access(path, F_OK)) {
        creat(path, S_IRWXO);
        chmod(path, S_IROTH|S_IWOTH|S_IRGRP|S_IWGRP|S_IRWXU|S_IRWXO|S_IRWXG);
    }
    fd = open(path, O_RDWR);
    if (fd < 0) {
        LOGE("open %s fail, err= %s\n", path, strerror(errno));
		ret = -1;
        goto out;
    }
    count = 0;
    ftruncate(fd, 0);
    lseek(fd, sizeof(count), SEEK_SET);
    list_for_each_entry_safe(data_list, temp_list, head, list) {//掉电只保存离线数据，不删除链表,有可能时工作过程中抖动导致的瞬间掉电
        write(fd, data_list->data, data_list->len);
        //__list_del_entry(&data_list->list);
        //free(data_list->data);
        //free(data_list);
        if (count++ > GPS_MAX_DATA)
            break;
    }
    //INIT_LIST_HEAD(head);
    ret = count;
    lseek(fd, 0, SEEK_SET);
    write(fd, &count, sizeof(count));
    close(fd);
out:
    pthread_mutex_unlock(&mutex_offline_block_rw);
    pthread_mutex_unlock(&mutex_list);

    return ret;
}

int  openUltra() {
    ultra_fd = open(ULTRA_PATH, O_RDWR | O_NOCTTY | O_NDELAY);
    if (ultra_fd < 0) {
        LOGE("open %s fail, err= %s\n", "xxx", strerror(errno));
        return -1;
    }
    ALOGE("open %s sucess, fd = %d\n", ULTRA_PATH, ultra_fd);
    return ultra_fd;
}

void closeUltra(void) {
    close(ultra_fd);
}


int readUltra(void) { //时间在驱动中计算，读出来大于0有效；
#if 0
    int usecond = -1;
    //sleepMsec(30);
    int ret = read(ultra_fd, &usecond, sizeof(usecond));
    //LOGE("%s usecond=%d", __func__, usecond);
    if (ret != sizeof(usecond))
        usecond = -1;

    return  usecond;
#endif
    return 0;
}

int writeUltra(int trig_gpioVal) {
    char val = trig_gpioVal > 0 ? 1 : 0;

    return write(ultra_fd, &val, sizeof(val));
}

void TRIG_HIGH(void) {
    writeUltra(1);
}

void TRIG_LOW(void) {
    writeUltra(0);
}

int open_led() {
    fd_led = open(LED_PATH, O_RDWR);
    if(fd_led < 0) {
        ALOGE("fail to open file %s", LED_PATH);
        return -1;
    }
    return 0;
}

void close_led() {
    if (fd_led > 0)
        close(fd_led);
}
//D1
#define DEC(x) (x-1)
#define D1_A DEC(27)
#define D1_B DEC(28)
#define D1_C DEC(22)
#define D1_D DEC(23)
#define D1_E DEC(24)
#define D1_F DEC(26)
#define D1_G DEC(25)
#define D1_DP DEC(21)

#define D2_A DEC(31)
#define D2_B DEC(32)
#define D2_C DEC(18)
#define D2_D DEC(19)
#define D2_E DEC(20)
#define D2_F DEC(30)
#define D2_G DEC(29)
#define D2_DP DEC(17)

#define D3_A DEC(11)
#define D3_B DEC(12)
#define D3_C DEC(6)
#define D3_D DEC(7)
#define D3_E DEC(8)
#define D3_F DEC(10)
#define D3_G DEC(9)
#define D3_DP DEC(5)

#define D4_A DEC(15)
#define D4_B DEC(16)
#define D4_C DEC(2)
#define D4_D DEC(3)
#define D4_E DEC(4)
#define D4_F DEC(14)
#define D4_G DEC(13)
#define D4_DP DEC(1)

#define SYSTEM_LED (1LL<<DEC(36))
#define GPS_LED (1LL<<DEC(35))
#define GSM_LED (1LL<<DEC(34))
#define ALARM_LED (1LL<<DEC(33))
#define DISP_ERROR 11
static const long long led0_table[13] = {
    (1LL<<D1_A)|(1LL<<D1_B)|(1LL<<D1_C)|(1LL<<D1_D)|(1LL<<D1_E)|(1LL<<D1_F),//0
    (1LL<<D1_B)|(1LL<<D1_C),//1
    (1LL<<D1_A)|(1LL<<D1_B)|(1LL<<D1_G)|(1LL<<D1_E)|(1LL<<D1_D),//2
    (1LL<<D1_A)|(1LL<<D1_B)|(1LL<<D1_G)|(1LL<<D1_C)|(1LL<<D1_D),//3
    (1LL<<D1_F)|(1LL<<D1_G)|(1LL<<D1_B)|(1LL<<D1_C),//4
    (1LL<<D1_A)|(1LL<<D1_F)|(1LL<<D1_G)|(1LL<<D1_C)|(1LL<<D1_D),//5
    (1LL<<D1_A)|(1LL<<D1_F)|(1LL<<D1_G)|(1LL<<D1_C)|(1LL<<D1_D)|(1LL<<D1_E),//6
    (1LL<<D1_A)|(1LL<<D1_B)|(1LL<<D1_C),//7
    (1LL<<D1_A)|(1LL<<D1_B)|(1LL<<D1_C)|(1LL<<D1_D)|(1LL<<D1_E)|(1LL<<D1_F)|(1LL<<D1_G),//8
    (1LL<<D1_A)|(1LL<<D1_B)|(1LL<<D1_C)|(1LL<<D1_D)|(1LL<<D1_F)|(1LL<<D1_G),//9
    (1LL<<D1_DP),//.
    (1LL<<D1_A)|(1LL<<D1_D)|(1LL<<D1_E)|(1LL<<D1_F)|(1LL<<D1_G),//E
    (1LL<<D1_G),//-
};

static const long long led1_table[13] = {
    (1LL<<D2_A)|(1LL<<D2_B)|(1LL<<D2_C)|(1LL<<D2_D)|(1LL<<D2_E)|(1LL<<D2_F),//0
    (1LL<<D2_B)|(1LL<<D2_C),//1
    (1LL<<D2_A)|(1LL<<D2_B)|(1LL<<D2_G)|(1LL<<D2_E)|(1LL<<D2_D),//2
    (1LL<<D2_A)|(1LL<<D2_B)|(1LL<<D2_G)|(1LL<<D2_C)|(1LL<<D2_D),//3
    (1LL<<D2_F)|(1LL<<D2_G)|(1LL<<D2_B)|(1LL<<D2_C),//4
    (1LL<<D2_A)|(1LL<<D2_F)|(1LL<<D2_G)|(1LL<<D2_C)|(1LL<<D2_D),//5
    (1LL<<D2_A)|(1LL<<D2_F)|(1LL<<D2_G)|(1LL<<D2_C)|(1LL<<D2_D)|(1LL<<D2_E),//6
    (1LL<<D2_A)|(1LL<<D2_B)|(1LL<<D2_C),//7
    (1LL<<D2_A)|(1LL<<D2_B)|(1LL<<D2_C)|(1LL<<D2_D)|(1LL<<D2_E)|(1LL<<D2_F)|(1LL<<D2_G),//8
    (1LL<<D2_A)|(1LL<<D2_B)|(1LL<<D2_C)|(1LL<<D2_D)|(1LL<<D2_F)|(1LL<<D2_G),//9
    (1LL<<D2_DP),//.
    (1LL<<D2_A)|(1LL<<D2_D)|(1LL<<D2_E)|(1LL<<D2_F)|(1LL<<D2_G),//E
    (1LL<<D2_G),//-
};

static const long long led2_table[13] = {
    (1LL<<D3_A)|(1LL<<D3_B)|(1LL<<D3_C)|(1LL<<D3_D)|(1LL<<D3_E)|(1LL<<D3_F),//0
    (1LL<<D3_B)|(1LL<<D3_C),//1
    (1LL<<D3_A)|(1LL<<D3_B)|(1LL<<D3_G)|(1LL<<D3_E)|(1LL<<D3_D),//2
    (1LL<<D3_A)|(1LL<<D3_B)|(1LL<<D3_G)|(1LL<<D3_C)|(1LL<<D3_D),//3
    (1LL<<D3_F)|(1LL<<D3_G)|(1LL<<D3_B)|(1LL<<D3_C),//4
    (1LL<<D3_A)|(1LL<<D3_F)|(1LL<<D3_G)|(1LL<<D3_C)|(1LL<<D3_D),//5
    (1LL<<D3_A)|(1LL<<D3_F)|(1LL<<D3_G)|(1LL<<D3_C)|(1LL<<D3_D)|(1LL<<D3_E),//6
    (1LL<<D3_A)|(1LL<<D3_B)|(1LL<<D3_C),//7
    (1LL<<D3_A)|(1LL<<D3_B)|(1LL<<D3_C)|(1LL<<D3_D)|(1LL<<D3_E)|(1LL<<D3_F)|(1LL<<D3_G),//8
    (1LL<<D3_A)|(1LL<<D3_B)|(1LL<<D3_C)|(1LL<<D3_D)|(1LL<<D3_F)|(1LL<<D3_G),//9
    (1LL<<D3_DP),//.
    (1LL<<D3_A)|(1LL<<D3_D)|(1LL<<D3_E)|(1LL<<D3_F)|(1LL<<D3_G),//E
    (1LL<<D3_G),//-
};

static const long long led3_table[13] = {
    (1LL<<D4_A)|(1LL<<D4_B)|(1LL<<D4_C)|(1LL<<D4_D)|(1LL<<D4_E)|(1LL<<D4_F),//0
    (1LL<<D4_B)|(1LL<<D4_C),//1
    (1LL<<D4_A)|(1LL<<D4_B)|(1LL<<D4_G)|(1LL<<D4_E)|(1LL<<D4_D),//2
    (1LL<<D4_A)|(1LL<<D4_B)|(1LL<<D4_G)|(1LL<<D4_C)|(1LL<<D4_D),//3
    (1LL<<D4_F)|(1LL<<D4_G)|(1LL<<D4_B)|(1LL<<D4_C),//4
    (1LL<<D4_A)|(1LL<<D4_F)|(1LL<<D4_G)|(1LL<<D4_C)|(1LL<<D4_D),//5
    (1LL<<D4_A)|(1LL<<D4_F)|(1LL<<D4_G)|(1LL<<D4_C)|(1LL<<D4_D)|(1LL<<D4_E),//6
    (1LL<<D4_A)|(1LL<<D4_B)|(1LL<<D4_C),//7
    (1LL<<D4_A)|(1LL<<D4_B)|(1LL<<D4_C)|(1LL<<D4_D)|(1LL<<D4_E)|(1LL<<D4_F)|(1LL<<D4_G),//8
    (1LL<<D4_A)|(1LL<<D4_B)|(1LL<<D4_C)|(1LL<<D4_D)|(1LL<<D4_F)|(1LL<<D4_G),//9
    (1LL<<D4_DP),//.
    (1LL<<D4_A)|(1LL<<D4_D)|(1LL<<D4_E)|(1LL<<D4_F)|(1LL<<D4_G),//E
    (1LL<<D4_G),//-
};

long long led_encode(int disp) {
    char buf[10];
    int len;
    long long value = 0;
    char ge, shi, bai, qian;
    int para = disp;

    //para = 5678;

	if (para == LED_GPS_ERROR) {
		value = led2_table[DISP_ERROR] | led3_table[1];
	}
	else if (para == LED_ULTRA_ERROR) {
		value = led2_table[DISP_ERROR] | led3_table[2];
	}
	else if (para == LED_BLACK) {
		value = 0;
    } else if (para == LED_TEST) {
        value = led0_table[8] | led1_table[8] | led2_table[8] | led3_table[8]
            | led0_table[10] | led1_table[10] | led2_table[10] | led3_table[10];
    } else if (para < 0) {//显示标定角度,不带小数位
        para = abs(para)/10;
        len = sprintf(buf, "%d", para);
        if (len > 3)
            len = 3;
        switch (len) {
            case 1:
                value = led3_table[para];
                value |= led2_table[12];
                break;
            case 2:
                value = led2_table[para/10] | led3_table[para%10];
                value |= led1_table[12];
                break;
            case 3:
                value = led1_table[para/100] | led2_table[(para%100)/10] | led3_table[(para%100)%10];
                value |= led0_table[12];
                break;
            default:
                break;
        }
    } else {
        len = sprintf(buf, "%d", para);
        if (len > 4)
            len = 4;
        switch (len) {
            case 1:
                value = led2_table[0] | led3_table[para];//只有一位时候前面要补显一个0
                value |= led2_table[10];//小数点
                break;
            case 2:
                value = led2_table[para/10] | led3_table[para%10];
                value |= led2_table[10];//小数点
                break;
            case 3:
                value = led1_table[para/100] | led2_table[(para%100)/10] | led3_table[(para%100)%10];
                value |= led2_table[10];//小数点
                break;
            case 4:
                value = led0_table[para/1000] | led1_table[(para%1000)/100] | led2_table[((para%1000)%100)/10] | led3_table[((para%1000)%100)%10];
                value |= led2_table[10];//小数点
                break;
            default:
                break;
        }
    }
    
    return value;
}

int write_led(int disp, int system_led, int gps_led, int gsm_led, int alarm_led) {
    long long value;

    value = led_encode(disp);

    if (system_led)
        value |= SYSTEM_LED;
	if (gps_led) {
		value |= GPS_LED;
		gps_error = 0;
	}
	else
	{
		gps_error = 1;
	}
    if (gsm_led)
        value |= GSM_LED;
    
    if (alarm_led)
        value |= ALARM_LED;
    
    write(fd_led, &value, sizeof(value));
    return 0;
}

void disp_DeviceId(char* id)
{
	if (id == NULL)
		return;
	int para = atoi(id + 3);
	int disp_value = 0;
	disp_value = led0_table[(para % 10000) / 1000] | led1_table[(para % 1000) / 100] | led2_table[(para % 100) / 10] | led3_table[para % 10];
	write(fd_led, &disp_value, sizeof(disp_value));

}

int write_gpio(char *pin_name, int value) {
    int val = value == 1 ? '1' : '0';
    int fd = open(pin_name, O_WRONLY);
    int ret;

    if(fd < 0) {
        ALOGE("fail to open file %s", pin_name);
        return -1;
    }
    ret = write(fd, &val, sizeof(val));
    close(fd);
    return  ret; 
}

int read_gpio(char *pin_name) {
    char val = -1;
    int fd = open(pin_name, O_RDONLY);
    if(fd < 0) {
        ALOGE("fail to open file %s", pin_name);
        return -1;
    }
    read(fd, &val, sizeof(val));
    close(fd);
    return  val == '1' ? 1 : 0; 
}


void *mcu_communication(void *arg) {
    unsigned char data;
    int mcu_uart_fd = -1;

    for (;;) {
        sleepMsec(10);
        if (mcu_uart_fd < 0) {
            mcu_uart_fd = open("/dev/ttyS7", O_RDWR);
            if (mcu_uart_fd < 0)
                continue;
            set_baudrate(mcu_uart_fd, "B9600");
        }
        int ret = read(mcu_uart_fd, &data, 1);
        if (ret > 0) {
            //LOGE("mcu uart data=%x", data);
            data++;
            write(mcu_uart_fd, &data, 1);
        }
    }
}


//int openGps(char *path, int flags) {
//    int fd = open(path, flags > 0 ? flags : O_RDWR | O_NOCTTY | O_NDELAY);
//    if (fd <= 0) {
//        ALOGE("open fd err[%s, %s]\n", path, strerror(errno));
//        return -1;
//    }
//    //  ALOGE("open %s sucess, fd = %d\n", path, fd);
//
//    epoll_gpsfd = epoll_create(1);
//    epoll_register(epoll_gpsfd, fd);
//
//    return fd;
//}
//
//void closeGps() {
//    epoll_deregister(epoll_gpsfd, fd_gps);
//    close(fd_gps);
void write_gps_info(const char *fmt, ...) {
    FILE *fp;
    char buf[1024];
    va_list ap;

    pthread_mutex_lock(&mutex_gpsData_lock);
    va_start(ap, fmt);
    vsnprintf(buf, sizeof(buf), fmt, ap);
    va_end(ap);
    fp = fopen(GPS_DATA_LOG_PATH, "at+");
    if (!fp) {
        LOGE("open gpsData.txt error[%s], quit", strerror(errno));
        goto out ;
    }
    fwrite(buf, 1, strlen(buf), fp);
    fwrite("\r\n", 1, 2, fp);
    fclose(fp);
out:
    pthread_mutex_unlock(&mutex_gpsData_lock);
}

void write_gps_area_info(const char* fmt, ...) {
	FILE* fp;
	char buf[1024];
	va_list ap;

	pthread_mutex_lock(&mutex_gpsAreaData_lock);
	va_start(ap, fmt);
	vsnprintf(buf, sizeof(buf), fmt, ap);
	va_end(ap);
	fp = fopen(GPS_AREA_DATA_LOG_PATH, "at+");
	if (!fp) {
		LOGE("open gpsAreaData.txt error[%s], quit", strerror(errno));
		goto out;
	}
	fwrite(buf, 1, strlen(buf), fp);
	fwrite("\r\n", 1, 2, fp);
	fclose(fp);
out:
	pthread_mutex_unlock(&mutex_gpsAreaData_lock);
}

void write_log_to_sdcard(char *path, const char *fmt, ...) {
    FILE *fp;
    long ts;
    va_list ap;
    char buf[1024];
    char time_str[128];
    struct tm *tm;

    pthread_mutex_lock(&mutex_log_lock);
    ts = time(NULL);
    tm = localtime(&ts);
    va_start(ap, fmt);
    vsnprintf(buf, sizeof(buf), fmt, ap);
    va_end(ap);

    sprintf(time_str, "%d-%02d-%02d %02d:%02d:%02d  ", (1900+tm->tm_year), 1+tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
    fp = fopen(path, "at+");
    if (!fp) {
        //LOGE("open %s error[%s], quit", path, strerror(errno));
        goto out;
    }
    fwrite(time_str, 1, strlen(time_str), fp);
    fwrite(buf, 1, strlen(buf), fp);
    fwrite("\r\n", 1, 2, fp);
    fclose(fp);
out:
    pthread_mutex_unlock(&mutex_log_lock);
}

long currentTimeInSec() {
	struct timeval tv;
	gettimeofday(&tv, NULL);
	return tv.tv_sec + tv.tv_usec / 1000000;
}



